﻿using HarfBuzzSharp;
using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using netDxf.Entities;
using SkiaSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using LightCAD.MathLib;
using Avalonia.Controls;
using Avalonia.Media.TextFormatting.Unicode;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Avalonia.Rendering;

/*
 * Jmoons
 * 20230928:
 * 目前支持line作为裁剪元素，园作为内外轮廓
 * 问题：
 * 1.如何更通用的判定轮廓是否闭合（异性轮廓？）
 * 2.轮廓闭合的前提下，如何通用的判断点处于轮廓内
 * 3.诸如矩形（polyline）如何拆解
 * 4.Lcline的cross判定为射线，需要和线段区分
 */

namespace LightCAD.Drawing.Actions
{
    public class ClipAction : ElementAction
    {
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;

        private List<LcElement> clip_patterns = new List<LcElement>();
        private LcElement out_contour;
        private List<LcElement> in_contour = new List<LcElement>();
       
        private string _methodName;

        private enum ClipType
        {
            INSIDE = 0,
            OUTSIDE = 1,
            COMPLEX = 2,
        }
        private ClipType ClipActionType = ClipType.INSIDE;

        static ClipAction()
        {
            CommandName = "CLIP";
            CreateMethods = new LcCreateMethod[1];

            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "SINGLE",
                Description = "裁剪",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="Step0", Options="指定裁剪方式 [内部(I)/外部(O)/复合(C)]:" },
                    new LcCreateStep{ Name="Step1", Options="裁剪对象 [完成(G)]:" },
                    new LcCreateStep{ Name="Step2", Options="指定外轮廓:" },
                    new LcCreateStep{ Name="Step3", Options="指定内轮廓 [完成(G)]:" },
                }
            };

           
        }

        internal static void Initilize()
        {
        }

        private PointInputer PointInputer { get; set; }
        public ClipAction() { }
        public ClipAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令 ：CLIP");
        }
        private LcCreateMethod GetMethod(string method)
        {
            if (method == null) return CreateMethods[0];
            var getted = CreateMethods.FirstOrDefault((m) => m.Name == method);
            if (getted == null)
                return CreateMethods[0];
            else
                return getted;
        }
        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            var method = "SINGLE";
            if (args != null && args.Length > 0)
            {
                method = args[0];
            }
            var curMethod = this.GetMethod(method);
            _methodName = curMethod.Name;

            Console.WriteLine(_methodName);

            var ElementInputer = new ElementInputer(this.docEditor);
            this.PointInputer = new PointInputer(this.docEditor);

            if (curMethod.Name == "SINGLE") goto Method_NAVIGATE_Step0;
            else goto Method_NAVIGATE_Step0;

        Method_NAVIGATE_Step0:
            {
                curMethod = this.SetCurMethod(CreateMethods, 0);
                var navigate_step0 = curMethod.Steps[0];
                var navigate_result0 = await PointInputer.Execute(navigate_step0.Options);
                clip_patterns.Clear();
                in_contour.Clear(); 
                if (PointInputer.isCancelled) { this.Cancel(); return; }
                // zcb: 增加Res0为空的判定
                if (navigate_result0 == null)
                {
                    this.Cancel();
                    goto End;
                }
                if (navigate_result0.ValueX == null)
                {
                    if (navigate_result0.Option != null)
                    {
                        if (navigate_result0.Option.ToUpper() == "I")
                        {
                            ClipActionType = ClipType.INSIDE;
                            goto Method_NAVIGATE_Step1;
                        }
                        else if (navigate_result0.Option.ToUpper() == "O")
                        {
                            ClipActionType = ClipType.OUTSIDE;
                            goto Method_NAVIGATE_Step1;
                        }
                        else if (navigate_result0.Option.ToUpper() == "C")
                        {
                            ClipActionType = ClipType.COMPLEX;
                            goto Method_NAVIGATE_Step1;
                        }
                        else
                        {
                            goto Method_NAVIGATE_Step0;
                        }
                    }
                    else
                    {
                        goto Method_NAVIGATE_Step0;
                    }
                }
            }

        Method_NAVIGATE_Step1:
            {
                var navigate_step1 = curMethod.Steps[1];
                var navigate_result1 = await ElementInputer.Execute(navigate_step1.Options);

                if (ElementInputer.isCancelled) { this.Cancel(); return; }
                // zcb: 增加Res0为空的判定
                if (navigate_result1 == null)
                {
                    this.Cancel();
                    goto End;
                }

                if (navigate_result1.ValueX == null)
                {
                    if (navigate_result1.Option != null && navigate_result1.Option.ToUpper() == "G")
                    {
                        goto Method_NAVIGATE_Step2;
                    }
                    else
                    {
                        goto Method_NAVIGATE_Step1;
                    }
                }
                else
                {
                    if (navigate_result1.Option != null && navigate_result1.Option.ToUpper() == "G")
                    {
                        goto Method_NAVIGATE_Step2;
                    }
                    else
                    {
                        LcElement element = (LcElement)navigate_result1.ValueX;
                        if(!clip_patterns.Contains(element))
                            clip_patterns.Add(element);
                        goto Method_NAVIGATE_Step1;
                    }
                }
            }

        Method_NAVIGATE_Step2:
            {
                var navigate_step2 = curMethod.Steps[2];
                var navigate_result2 = await ElementInputer.Execute(navigate_step2.Options);
                if (ElementInputer.isCancelled) { this.Cancel(); return; }
                // zcb: 增加Res0为空的判定
                if (navigate_result2 == null)
                {
                    this.Cancel();
                    goto End;
                }
                if (navigate_result2.ValueX == null)
                {
                    goto Method_NAVIGATE_Step2;
                }
                else
                {
                    this.out_contour = (LcElement)navigate_result2.ValueX;
                    if (ClipActionType == ClipType.INSIDE || ClipActionType == ClipType.OUTSIDE)
                    {
                        goto Method_NAVIGATE_Create;
                    }
                    else
                    {
                        goto Method_NAVIGATE_Step3;
                    }
                }
            }

        Method_NAVIGATE_Step3:
            {
                var navigate_step3 = curMethod.Steps[3];
                var navigate_result3 = await ElementInputer.Execute(navigate_step3.Options);
                if (ElementInputer.isCancelled) { this.Cancel(); return; }
                // zcb: 增加Res0为空的判定
                if (navigate_result3 == null)
                {
                    this.Cancel();
                    goto End;
                }
                if (navigate_result3.ValueX == null)
                {
                    if (navigate_result3.Option != null && navigate_result3.Option.ToUpper() == "G")
                    {
                        goto Method_NAVIGATE_Create;
                    }
                    else
                    {
                        goto Method_NAVIGATE_Step3;
                    }
                }
                else
                {
                    if (navigate_result3.Option != null && navigate_result3.Option.ToUpper() == "G")
                    {
                        goto Method_NAVIGATE_Create;
                    }
                    else
                    {
                        LcElement element = (LcElement)navigate_result3.ValueX;
                        if(!in_contour.Contains(element))
                            in_contour.Add(element);
                        goto Method_NAVIGATE_Step3;
                    }
                }
            }

        Method_NAVIGATE_Create:
            {
                if (ClipActionType == ClipType.INSIDE)
                {
                    Clip(clip_patterns, out_contour, false);
                }
                else if (ClipActionType == ClipType.OUTSIDE)
                {
                    Clip(clip_patterns, out_contour, true);
                }
                else if(ClipActionType == ClipType.COMPLEX)
                {
                    Clip(clip_patterns, out_contour, in_contour);
                }
                goto End;
            }

        End:
            this.EndCreating();

        }

        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
        }
        public override void CreateElement(LcElement element, Matrix3 matrix)
        {

        }
        public override void CreateElement(LcElement element, Vector2 basePoint, double scaleFactor)
        {

        }
        public override void CreateElement(LcElement element, Vector2 basePoint, Vector2 scaleVector)
        {

        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {

        }

        public override void DrawAuxLines(SKCanvas canvas)
        {
          
        }

        private void DrawAuxLine(SKCanvas canvas, Vector2 p0, Vector2 p1)
        {
            var sk_pre = this.vportRt.ConvertWcsToScr(p0).ToSKPoint();
            var sk_p = this.vportRt.ConvertWcsToScr(p1).ToSKPoint();
            //辅助元素的颜色 
            canvas.DrawLine(sk_pre, sk_p, Constants.auxElementPen);
            //辅助曲线的颜色，包括辅助长度，辅助角度等
        }

        private void Clip(List<LcElement> patterns, LcElement outcontour, List<LcElement> incontour)
        {
            List<LcElement> p = Clip(patterns, outcontour);
            //debug_show(p);

            if (incontour.Count > 0)
            {
                for(int i = 0; i < incontour.Count; i++)
                {
                    p = Clip(p, incontour[i], true);
                    //debug_show(p);
                }
            }
        }

        private void debug_show(List<LcElement> patterns)
        {
            string str = "";
            for (int i = 0;i<patterns.Count;i++)
            {
                var e = patterns[i];
                
                if (e is LcLine)
                {
                    LcLine line = (LcLine)e;
                    str += "Start: ";
                    str += line.Start.X.ToString("0.00");
                    str += ",";
                    str += line.Start.Y.ToString("0.00");
                    str += ",End: ";
                    str += line.End.X.ToString("0.00");
                    str += ",";
                    str += line.End.Y.ToString("0.00");
                    str += ", ";
                }
            }
            Console.WriteLine(str);
        }

        private List<LcElement> Clip(List<LcElement> patterns, LcElement contour, bool invert = false)
        {
            List<LcElement> tmp2 = new List<LcElement>(); 
            List<LcElement> todelete = new List<LcElement>();
            List<LcElement> rst = new List<LcElement> ();
            for (int index = 0; index < patterns.Count; index++)
            {
                LcLine? line = null;
                LcArc? arc = null;
                LcCircle? circle = null;

                Vector2 startpoint;
                Vector2 endpoint;
                Vector2 center;
                LcElement element = patterns.ElementAt(index);

                rst.Add(element);

                if(element is LcLine)
                {
                    line = element as LcLine;
                    startpoint = line.Start;
                    endpoint = line.End;
                }
                else if (element is LcArc)
                {
                    arc = element as LcArc;
                    startpoint = arc.Startp;
                    endpoint = arc.Endp;
                    center = arc.Center;
                }
                else if (element is LcCircle)
                {
                    circle = element as LcCircle;
                    startpoint = circle.Center + new Vector2 (circle.Radius,0.0);
                    endpoint = startpoint;
                    center = circle.Center;
                }
                else
                {
                    startpoint = null;
                    endpoint = null;
                }

                // 轮廓线与目标的交点
                List<Vector2> is_points = contour.GetCrossVectorByElement(element);
                List<Vector2> is_points2 = new List<Vector2>();

                // 需要在最后移除的元素（所有与轮廓有交点的元素）
                if (is_points.Count > 0)
                    todelete.Add(element);

                // 添加startpoint
                is_points2.Add(startpoint);

                // 添加交点
                if (is_points.Count == 1)
                {
                    is_points2.Add(is_points.ElementAt(0));
                }
                else if (is_points.Count > 1)
                {
                    Vector2 sp = startpoint;
                    //double sa = center.angleTo(sp);
                    //if (ellipse) sa = ellipse->getEllipseAngle(sp);
                    bool done;
                    double minDist;
                    double dist = 0.0;
                    Vector2? av;
                    Vector2 v;
                    Vector2? last = null;
                    do
                    {
                        done = true;
                        minDist = MathEx.MAX_VALUE;
                        av = null;
                        for (int i = 0; i < is_points.Count(); ++i)
                        {
                            v = is_points.ElementAt(i);
                            double a;
                            if (element is LcLine)
                            {
                                dist = sp.DistanceTo(v);
                            }
                            else if (element is LcArc)
                            {
                                ;// todo
                            }
                            else if (element is LcCircle)
                            {
                                ;// todo
                            }
                            else
                            {
                                ;// todo
                            }

                            if (dist < minDist)
                            {
                                // 可以用break跳出for？
                                minDist = dist;
                                done = false;
                                av = v;
                            }
                        }

                        if (!done && av!= null)
                        {
                            if (last == null || last.DistanceTo(av) > MathEx.EPSILON10)
                            {
                                is_points2.Add(av);
                                last = av;
                            }
                            is_points.Remove(av);

                            av=null;
                        }
                    } while (!done);
                }

                // 添加endpoint
                is_points2.Add(endpoint);

                // 将所有可能的小片段保存进tmp2
                for (int i = 1; i < is_points2.Count(); ++i)
                {
                    var v1 = is_points2.ElementAt(i - 1);
                    var v2 = is_points2.ElementAt(i);

                    if (line != null)
                    {
                        tmp2.Add(new LcLine(v1,v2));
                    }
                    else if (arc != null || circle != null)
                    {
                        ;// todo
                    }
                    else
                    {
                        ;// todo
                    }
                }
            }

            // 遍历所有小片段，所有中点位于轮廓内的保留
            for (int index = 0; index < tmp2.Count; index++)
            {
                var e = tmp2.ElementAt(index);
                Vector2? middlePoint = null;
                Vector2? middlePoint2 = null;

                if (e is LcLine)
                {
                    LcLine line = e as LcLine;
                    middlePoint = (line.Start + line.End) * 0.5;
                }
                else
                {
                    // todo
                }

                if (middlePoint != null)
                {
                    bool onContour = false;
                    bool isInContour = false;

                    if (contour is LcCircle)
                    {
                        LcCircle circle = contour as LcCircle;
                        double distp = Vector2.Distance(middlePoint, circle.Center);

                        if ((!invert && distp < circle.Radius) || (invert && distp > circle.Radius))
                        {
                            LcLine line = e as LcLine;
                            var doc = this.docRt.Document;
                            //DocumentManager.CurrentRecorder.BeginAction("line");
                            var lcele = doc.CreateObject<LcLine>(line.Start, line.End);
                            doc.ModelSpace.InsertElement(lcele);
                            //DocumentManager.CurrentRecorder.EndAction();
                            rst.Add(lcele);
                        }
                    }
                    else
                    {
                        // todo
                    }
                }
            }

            // 移除与轮廓存在交点的原始元素
            if(todelete.Count> 0)
            {
                for(int i = 0;i<todelete.Count;i++)
                {
                    rst.Remove(todelete[i]);
                    var doc = this.docRt.Document;
                    doc.ModelSpace.RemoveElement(todelete[i]);    
                }
            }

            // todo: 完善轮廓，元素的处理后，这里应该加上轮廓本身
            // rst.Add(contour);

            //
            return rst;
        }

        /// <summary>
        /// 获取两条线的夹角  
        /// </summary>
        /// <param name="line1start"></param>
        /// <param name="line1End"></param>
        /// <param name="line2start"></param>
        /// <param name="line2End"></param>
        /// <returns></returns>
        public double GetDegreesByTwoLine(Vector2 line1start, Vector2 line1End, Vector2 line2start, Vector2 line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;
            // 计算线段的向量表示
            double v1x = x2 - x1;
            double v1y = y2 - y1;
            double v2x = x4 - x3;
            double v2y = y4 - y3;
            // 计算向量的内积
            double dotProduct = v1x * v2x + v1y * v2y;
            // 计算向量的长度
            double magnitudeV1 = Math.Sqrt(v1x * v1x + v1y * v1y);
            double magnitudeV2 = Math.Sqrt(v2x * v2x + v2y * v2y);
            // 计算夹角余弦值
            double cosine = dotProduct / (magnitudeV1 * magnitudeV2);
            // 将夹角余弦值转换为角度
            double angleRadians = Math.Acos(cosine);
            double angleDegrees = angleRadians * 180 / Math.PI;
            return angleDegrees;
        }

        public Vector2 GetIntersectionOfTwoLines(Vector2 line1start, Vector2 line1End, Vector2 line2start, Vector2 line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;
            // 计算线段的向量表示
            double px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
            double py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
            return new Vector2(px, py);
        }

        #region Grip
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var grips = new List<ControlGrip>();
            return grips.ToArray();
        }

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {

        }


        public override void DrawDragGrip(SKCanvas canvas)
        {

        }

        #endregion

        public override List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>()
            {

            };
        }
    }
}
